package com.pi.dao.common;

import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;


import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.impl.CriteriaImpl.OrderEntry;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.pi.common.Assert;
import com.pi.common.BeanUtils;
import com.pi.tools.Page;
 

/**
 * GenericHibernateDao 继承 HibernateDao，简单封HibernateTemplate 各项功能
 * 基于Hibernate Dao 的编写
 * 
 * @author lny
 */
@SuppressWarnings("unchecked")
public class GenericHibernateDao<T extends Serializable, PK extends Serializable>
		extends HibernateDaoSupport implements GenericDao<T, PK> {
	// 实体类类�?由构造方法自动赋�?
	private Class<T> entityClass;

	// 构方法，根据实例类自动获取实体类类

	public Class<T> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	public GenericHibernateDao() {
		this.entityClass = null;
		Class c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}

	}

	// -------------------- 基本、增加修改、删除操--------------------

	// 根据主键获取实体。如果没有相应的实体，返null
	@Override
	public T get(PK id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	// 根据主键获取实体并加锁如果没有相应的实体，返回 null
	@Override
	public T getWithLock(PK id, LockMode lock) {
		T t = (T) getHibernateTemplate().get(entityClass, id, lock);
		if (t != null) {
			this.flush(); // 立即刷新，否则锁不会生效�?
		}
		return t;
	}

	// 根据主键获取实体。如果没有相应的实体，抛出异常
	@Override
	public T load(PK id) {
		return (T) getHibernateTemplate().load(entityClass, id);
	}

	// 根据主键获取实体并加锁如果没有相应的实体，抛出异常
	@Override
	public T loadWithLock(PK id, LockMode lock) {
		T t = (T) getHibernateTemplate().load(entityClass, id, lock);
		if (t != null) {
			this.flush(); // 立即刷新，否则锁不会生效
		}
		return t;
	}

	// 获取全部实体
	@Override
	public List<T> loadAll() {
		return (List<T>) getHibernateTemplate().loadAll(entityClass);
	}

	// loadAllWithLock()

	// 更新实体
	@Override
	public void update(T entity) {
		getHibernateTemplate().update(entity);
	}

	// 更新实体并加
	@Override
	public void updateWithLock(T entity, LockMode lock) {
		getHibernateTemplate().update(entity, lock);
		this.flush(); // 立即刷新，否则锁不会生效
	}

	// 存储实体到数据库
	@Override
	public void save(T entity) {
		getHibernateTemplate().save(entity);
	}
	
	@Override
	public void saveAll(List<T> entities) {
		 for (T entity : entities) {
			 getHibernateTemplate().save(entity);
		} 
	}

	// saveWithLock()

	// 增加或更新实
	@Override
	public void saveOrUpdate(T entity) {
		getHibernateTemplate().saveOrUpdate(entity);
	}

	// 增加或更新集合中的全部实
	@Override
	public void saveOrUpdateAll(Collection<T> entities) {
		getHibernateTemplate().saveOrUpdateAll(entities);
	}

	// 删除指定的实
	@Override
	public void delete(T entity) {
		getHibernateTemplate().delete(entity);
	}

	// 加锁并删除指定的实体
	@Override
	public void deleteWithLock(T entity, LockMode lock) {
		getHibernateTemplate().delete(entity, lock);
		this.flush(); // 立即刷新，否则锁不会生效
	}

	// 根据主键删除指定实体
	@Override
	public void deleteByKey(PK id) {
		this.delete(this.load(id));
	}

	// 根据主键加锁并删除指定的实体
	@Override
	public void deleteByKeyWithLock(PK id, LockMode lock) {
		this.deleteWithLock(this.load(id), lock);
	}

	// 删除集合中的全部实体
	@Override
	public void deleteAll(Collection<T> entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	// -------------------- HSQL ----------------------------------------------

	// 使用HSQL语句直接增加、更新删除实体
	@Override
	public int bulkUpdate(String queryString) {
		return getHibernateTemplate().bulkUpdate(queryString);
	}

	// 使用带参数的HSQL语句增加、更新删除实体
	@Override
	public int bulkUpdate(String queryString, Object[] values) {
		return getHibernateTemplate().bulkUpdate(queryString, values);
	}

	// 使用HSQL语句数据
	@Override
	public List find(String queryString) {
		return getHibernateTemplate().find(queryString);
	}

	// 使用带参数的HSQL语句数据
	@Override
	public List find(String queryString, Object[] values) {
		return getHibernateTemplate().find(queryString, values);
	}

	// 使用带命名的参数的HSQL语句数据
	@Override
	public List findByNamedParam(String queryString, String[] paramNames,
			Object[] values) {
		return getHibernateTemplate().findByNamedParam(queryString, paramNames,
				values);
	}

	// 使用命名的HSQL语句数据
	@Override
	public List findByNamedQuery(String queryName) {
		return getHibernateTemplate().findByNamedQuery(queryName);
	}

	// 使用带参数的命名HSQL语句数据
	@Override
	public List findByNamedQuery(String queryName, Object[] values) {
		return getHibernateTemplate().findByNamedQuery(queryName, values);
	}

	// 使用带命名参数的命名HSQL语句数据
	@Override
	public List findByNamedQueryAndNamedParam(String queryName,
			String[] paramNames, Object[] values) {
		return getHibernateTemplate().findByNamedQueryAndNamedParam(queryName,
				paramNames, values);
	}

	// 使用HSQL语句数据，返Iterator
	@Override
	public Iterator iterate(String queryString) {
		return getHibernateTemplate().iterate(queryString);
	}

	// 使用带参数HSQL语句数据，返Iterator
	@Override
	public Iterator iterate(String queryString, Object[] values) {
		return getHibernateTemplate().iterate(queryString, values);
	}

	// 关闭�返回Iterator
	@Override
	public void closeIterator(Iterator it) {
		getHibernateTemplate().closeIterator(it);
	}

	// -------------------------------- Criteria ------------------------------

	// 创建与会话无关的标准
	@Override
	public DetachedCriteria createDetachedCriteria() {
		return DetachedCriteria.forClass(this.entityClass);
	}

	// 创建与会话绑定的标准
	@Override
	public Criteria createCriteria() {
		return this.createDetachedCriteria().getExecutableCriteria(
				this.getSession());
	}

	// 满足标准的数
	@Override
	public List findByCriteria(DetachedCriteria criteria) {
		return getHibernateTemplate().findByCriteria(criteria);
	}

	//满足标准的数据，返回指定范围的记
	@Override
	public List findByCriteria(DetachedCriteria criteria, int firstResult,
			int maxResults) {
		return getHibernateTemplate().findByCriteria(criteria, firstResult,
				maxResults);
	}

	// 使用指定的实体及属（满足除主键外属性＝实体值）数据
	@Override
	public List<T> findEqualByEntity(T entity, String[] propertyNames) {
		Criteria criteria = this.createCriteria();
		Example exam = Example.create(entity);
		exam.excludeZeroes();
		String[] defPropertys = getSessionFactory().getClassMetadata(
				entityClass).getPropertyNames();
		for (String defProperty : defPropertys) {
			int ii = 0;
			for (ii = 0; ii < propertyNames.length; ++ii) {
				if (defProperty.equals(propertyNames[ii])) {
					criteria.addOrder(Order.asc(defProperty));
					break;
				}
			}
			if (ii == propertyNames.length) {
				exam.excludeProperty(defProperty);
			}
		}
		criteria.add(exam);
		return (List<T>) criteria.list();
	}

	// 使用指定的实体及属（满足属like 串实体�?）数
	@Override
	public List<T> findLikeByEntity(T entity, String[] propertyNames) {
//		Criteria criteria = this.createCriteria();
//		for (String property : propertyNames) {
//			try {
//				Object value = PropertyUtils.getProperty(entity, property);
//				if (value instanceof String) {
//					criteria.add(Restrictions.like(property, (String) value,
//							MatchMode.ANYWHERE));
//					criteria.addOrder(Order.asc(property));
//				} else {
//					criteria.add(Restrictions.eq(property, value));
//					criteria.addOrder(Order.asc(property));
//				}
//			} catch (Exception ex) {
//				// 忽略无效的检索参考数据�?
//			}
//		}
//		return (List<T>) criteria.list();
		return null;
	}

	// 使用指定的检索标准获取满足标准的记录
	@Override
	public Integer getRowCount(DetachedCriteria criteria) {
		criteria.setProjection(Projections.rowCount());
		List list = this.findByCriteria(criteria, 0, 1);
		return (Integer) list.get(0);
	}

	// 使用指定的检索标准检索数据，返回指定统计max,min,avg,sum)
	@Override
	public Object getStatValue(DetachedCriteria criteria, String propertyName,
			String StatName) {
		if (StatName.toLowerCase().equals("max"))
			criteria.setProjection(Projections.max(propertyName));
		else if (StatName.toLowerCase().equals("min"))
			criteria.setProjection(Projections.min(propertyName));
		else if (StatName.toLowerCase().equals("avg"))
			criteria.setProjection(Projections.avg(propertyName));
		else if (StatName.toLowerCase().equals("sum"))
			criteria.setProjection(Projections.sum(propertyName));
		else
			return null;
		List list = this.findByCriteria(criteria, 0, 1);
		return list.get(0);
	}

	//
	public List findByCriteria(Order order, Criterion... criterion) {
		Criteria crit = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterion) {
			crit.add(c);
		}
		if (order != null)
			crit.addOrder(order);
		return crit.list();
	}

	// 通用分页方式
	public List<T> findByCriteria(int firstResult, int rowCount, Order order,
			Criterion... criterion) {
		Criteria crit = getSession().createCriteria(entityClass);
		for (Criterion c : criterion) {
			crit.add(c);
		}
		if (order != null)
			crit.addOrder(order);
		crit.setFirstResult(firstResult);
		crit.setMaxResults(rowCount);
		return crit.list();
	}
	/**
	 * 去除hql的select子句。
	 * @param hql
	 * @return
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeSelect(String hql){
		Assert.hasText(hql);
		int beginPos = hql.toLowerCase().indexOf("from");
		Assert.isTrue(beginPos!=-1,hql);
		return hql.substring(beginPos);
	}
	/**
	 * 去除hql的orderBy子句。
	 * @param hql
	 * @return
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeOrders(String hql) {
		Assert.hasText(hql);
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}
	/**
	 * 创建一个Query对象。
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createQuery(String hql,Object...values){
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		for(int i = 0;i<values.length;i++){
			query.setParameter(i, values[i]);
		}
		return query;
	}
	/**
	 * query分页
	 * @param page
	 * @param hql
	 * @return
	 */
	@Override
	public Page findByQuery(String hql,Page p,Object...values) {
		Assert.hasText(hql);
		int pageNo = p.getPageIndex();
		int pageSize = p.getPageSize();
		Assert.isTrue(pageNo>=1);
		List data = new ArrayList<T>();
		List Alldata = new ArrayList<T>();
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		String countQueryString = "select count(*) " + removeSelect(removeOrders(hql));
		List countList = find(countQueryString, values);
		String totalCount = countList.get(0).toString();
		long count = Long.valueOf(totalCount);
		if(count < 1){
			return new Page(startIndex,count,pageSize,data,Alldata);
		}
		Query query = createQuery(hql,values);
		if(p.getSfdc().equals("1")){ 
		     Alldata = query.list();
		}else data = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return new Page(startIndex,count,pageSize,data,Alldata);
		 
	}
	/**
	 * 创建Criteria对象。
	 * @param <T>
	 * @param entityClass
	 * @param criterions
	 * @return
	 */
	@SuppressWarnings("hiding")
	private <T>Criteria createCriteria(Class<T> entityClass,Criterion...criterions){
		Criteria criteria = getSession().createCriteria(entityClass);
		
		for(Criterion c:criterions){
			criteria.add(c);
		}
		return criteria;
	}

	/**
	 * 分页查询带排序
	 * @param entityClass
	 * @param pageNo
	 * @param pageSize
	 * @param orderBy
	 * @param isAsc
	 * @param criterions
	 * @return
	 */
	@Override
	public Page findByCriteria(Class<T> entityClass,Page p,Criterion...criterions){
		Criteria criteria = createCriteria(entityClass,criterions);
		return findByCriteria(criteria,p);
	}
	/**
	 * 分页 通过criteria
	 * @param criteria
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	private Page findByCriteria(Criteria criteria,Page p){
		Assert.notNull(criteria);
		int pageNo = p.getPageIndex();
		int pageSize = p.getPageSize();
		Assert.isTrue(pageNo>=1);
		List data = new ArrayList<T>();
		List Alldata = new ArrayList<T>();
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		CriteriaImpl criteriaImpl = (CriteriaImpl) criteria;
		
		//先把Projection和OrderBy条件取出来,清空两者来执行Count操作
		Projection projection = (Projection) criteriaImpl.getProjection();
		List<CriteriaImpl.OrderEntry> orderEntitys = null;
		try {
			orderEntitys=(List<OrderEntry>) BeanUtils.forceGetProperty(criteriaImpl, "orderEntries");
			BeanUtils.forceSetProperty(criteriaImpl, "orderEntries", new ArrayList());
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		//取得总的数据数
		 long totalCount = Long.valueOf(criteria.setProjection(Projections.rowCount()).uniqueResult().toString());
		//将之前的Projection和OrderBy条件重新设回去
		criteria.setProjection(projection);
		if (projection == null) {
			criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		}
		
		try {
			BeanUtils.forceSetProperty(criteriaImpl, "orderEntries", orderEntitys);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		if(totalCount<1)
			return new Page(startIndex, totalCount, pageSize,data,Alldata); 
		if(p.getSfdc().equals("1")){ 
		     Alldata = criteria.list();
		}else data = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return new Page(startIndex, totalCount, pageSize, data,Alldata);
	}
	
//---------------------------------- Others -----------------------------------------------------------------

	// 加锁指定的实
	@Override
	public void lock(T entity, LockMode lock) {
		getHibernateTemplate().lock(entity, lock);
	}

	// 强制初始化指定的实体
	@Override
	public void initialize(Object proxy) {
		getHibernateTemplate().initialize(proxy);
	}

	// 强制立即更新缓冲数据到数据库（否则仅在事务提交时才更新）
	@Override
	public void flush() {
		getHibernateTemplate().flush();
	}

	// 强制立即清除缓冲数据
	@Override
	public void clear() {
		getHibernateTemplate().clear();
	}
//-----------------------------sql语句--------------------------------
	/**
	 * 根据sql语句获取数组列表
	 * @param sql
	 * @param values
	 * @return
	 */
	@Override
	public Page getObsPageBySQL(String sql,Page p, Object... values){
		Assert.hasText(sql);
		int pageNo = p.getPageIndex();
		int pageSize = p.getPageSize();
		Assert.isTrue(pageNo>=1);
		boolean T = true;
		if(sql.contains("distinct")){
			 T = false;
		}
		List data = new ArrayList<Object[]>();
		List Alldata = new ArrayList<Object[]>();
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		String countSQLQueryString = "";
		String select = removeOrders(sql);
		if(T){
		   countSQLQueryString = "select count(*) " + removeSelect(select);
		}else{
		   String str = select.substring(select.indexOf("select")+6, select.indexOf(","));  
		   countSQLQueryString = "select count(" + str+ ") " + removeSelect(select);
		}
		Query query = createSQLQueryCount(countSQLQueryString, values);
		List countList = query.list();
		if(countList.size()==0){
			return new Page(startIndex, 0, pageSize, data,Alldata); 
		}
		String totalCount = countList.get(0).toString();
		long count = Long.valueOf(totalCount);
		query = createSQLQuery(sql,values);
		if(p.getSfdc().equals("1")){ 
		     Alldata = query.list();
		}else data = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return new Page(startIndex,count,pageSize,data,Alldata);
	}
	/**
	 * 创建一个查询SQL语句总记录数的Query对象。
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createSQLQueryCount(String sql,Object...values){
		Assert.hasText(sql);
		Query query = getSession().createSQLQuery(sql);   
		for(int i = 0;i<values.length;i++){
			query.setParameter(i, values[i]);
		}
		return query;
	}
	
	/**
	 * 创建一个SQL语句的Query对象。
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createSQLQuery(Class<T> entityClass,String sql,Object...values){
		Assert.hasText(sql);
		Query query = getSession().createSQLQuery(sql).addEntity(entityClass);   
		for(int i = 0;i<values.length;i++){
			query.setParameter(i, values[i]);
		}
		return query;
	}
	/**
	 * 创建一个SQL语句的Query对象。
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createSQLQuery(String sql,Object...values){
		Assert.hasText(sql);
		Query query = getSession().createSQLQuery(sql);   
		for(int i = 0;i<values.length;i++){
			query.setParameter(i, values[i]);
		}
		return query;
	}

	/**
	 * 分页 通过sql进行
	 * 
	 * 
	 * @param sql
	 * @param pageNo
	 * @param pageSize
	 * @param values
	 * @return
	 */
	@Override
	public Page pagedSQLQuery(Class<T> entityClass,String sql,Page p,Object...values){
		Assert.hasText(sql);
		int pageNo = p.getPageIndex();
		int pageSize = p.getPageSize();
		Assert.isTrue(pageNo>=1);
		List data = new ArrayList<T>();
		List Alldata = new ArrayList<T>();
		int startIndex = Page.getStartOfPage(pageNo, pageSize);
		String countSQLQueryString = "select count(*) " + removeSelect(removeOrders(sql));
		Query query = createSQLQueryCount(countSQLQueryString, values);
		List countList = query.list();
		String totalCount = countList.get(0).toString();
		long count = Long.valueOf(totalCount);
		if(count<1){
			return new Page(startIndex, count, pageSize, data,Alldata); 
		}
		query = createSQLQuery(entityClass,sql,values);
		if(p.getSfdc().equals("1")){ 
		     Alldata = query.list();
		}else data = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return new Page(startIndex,count,pageSize,data,Alldata);
	}
	/**
	 * 根据sql获取列表
	 * @param entityClass
	 * @param sql
	 * @param values
	 * @return
	 */
	@Override
	public  List<T> getListBySQL(Class<T> entityClass,String sql,Object ...values){
		Assert.hasText(sql);
		List data = new ArrayList<T>();
		Query query = createSQLQuery(entityClass, sql, values);
		data = query.list();
		return data;
	}
}
